package mspbots.cw.client.core.data.callbacks;

import com.fasterxml.jackson.databind.JsonNode;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import mspbots.cw.client.core.AbstractToolsUtil;
import mspbots.cw.client.core.client.ClientProperties;
import mspbots.cw.common.QueryParams;
import mspbots.cw.common.callback.CallbackEntityType;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * com.mspbots.sync.callback.WiseCallbackService
 *
 * @author Alex bob(https://github.com/vnobo)
 * @date Created by 2019/10/9
 */
@Log4j2
@Service
@RequiredArgsConstructor
public class CallbacksServiceImpl extends AbstractToolsUtil {

    private final NoticeProperties noticeProperties;

    public Flux<JsonNode> initialize(ClientProperties properties) {
        return Flux.concat(this.delAll(properties), Flux.fromStream(Arrays.stream(CallbackEntityType.values()).distinct())
                .map(val -> CallbackParam.withType(val.name())
                        .setUrl("https://" + this.noticeProperties.getHost() + "/notice/"
                                + properties.getTenantId() + "/callback?id="))
                .flatMap(this::post))
                .contextWrite(ctx -> ctx.put("properties", properties));
    }

    public Flux<JsonNode> delAll(ClientProperties properties) {
        return this.get(QueryParams.withDefault().setConditions("url contains '" + this.noticeProperties.getHost() + "'"))
                .flatMap(jsonNode -> this.delete(jsonNode.get("id").intValue()).map(v -> jsonNode))
                .contextWrite(ctx -> ctx.put("properties", properties));
    }

    public Flux<JsonNode> get(Long tenant) {
        return this.loadProperties(tenant)
                .flatMapMany(properties -> this.get(QueryParams.withDefault())
                        .contextWrite(ctx -> ctx.put("properties", properties)));
    }

    public Mono<Object> put(Long tenant, Integer id, CallbackParam body) {
        if (ObjectUtils.isEmpty(body.getUrl())) {
            body.setUrl("https://" + this.noticeProperties.getHost() + "/wise/notice/" + tenant + "/callback");
        }
        return this.loadProperties(tenant)
                .flatMap(properties -> super.cwWebClient.put("/system/callbacks/" + id, body)
                        .contextWrite(ctx -> ctx.put("properties", properties)));
    }

    public Flux<JsonNode> delete(Long tenant) {
        return this.loadProperties(tenant).flatMapMany(this::delAll);
    }

    public Flux<JsonNode> batchAdd(Long tenant, List<CallbackParam> params) {
        return this.loadProperties(tenant)
                .flatMapMany(property -> Flux.fromStream(params.parallelStream())
                        .flatMap(this::post)
                        .contextWrite(ctx -> ctx.put("properties", property)));
    }

    public Flux<JsonNode> post(Long tenant) {
        return this.loadProperties(tenant).flatMapMany(this::initialize);
    }

    private Mono<JsonNode> post(CallbackParam body) {
        log.debug("Add call back body: {}", body);
        return this.cwWebClient.post("/system/callbacks", body)
                .onErrorResume(err -> {
                    log.error("Add call back error,body: {}, msg: {}", body, err.getMessage());
                    return Mono.empty();
                });
    }

    private Flux<JsonNode> get(QueryParams queryParams) {
        return super.cwWebClient.fetch("/system/callbacks", queryParams);
    }

    private Mono<Boolean> delete(Integer id) {
        log.debug("Delete call back id: {}", id);
        return super.cwWebClient.delete("/system/callbacks/{id}", Map.of("id", id))
                .onErrorResume(err -> {
                    log.error("Delete call back error,id: {}, msg: {}", id, err.getMessage());
                    return Mono.empty();
                });
    }

}
